﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace NFinal.Owin
{
    /// <summary>
    /// 输出Html类
    /// </summary>
    public class HtmlWriter
    {
        /// <summary>
        /// utf-8编码
        /// </summary>
        private readonly static Encoding encoding = new UTF8Encoding(false);
        /// <summary>
        /// html header头
        /// </summary>
        public IDictionary<string, string[]> headers = null;
        /// <summary>
        /// Set-Cookie的值存储
        /// </summary>
        public IDictionary<string,string> setCookies = null;
        /// <summary>
        /// owin 参数
        /// </summary>
        public IDictionary<string, object> environment = null;
		public long contentLength = 0;
        Stream stream = null;
        /// <summary>
        /// Html类初始化
        /// </summary>
        /// <param name="environment">owin参数</param>
        /// <param name="headers">headers头</param>
        public HtmlWriter(IDictionary<string, object> environment,IDictionary<string,string[]> headers)
        {
            this.environment = environment;
            //stream = (Stream)environment["owin.ResponseBody"];
            stream = new MemoryStream();
            this.headers = (IDictionary<string, string[]>)environment["owin.ResponseHeaders"];
            foreach (var header in headers)
            {
                this.headers.Add(header.Key, header.Value);
            }
            setCookies = new Dictionary<string, string>();
        }
        /// <summary>
        /// Html类初始化
        /// </summary>
        /// <param name="environment">owin参数</param>
        public HtmlWriter(IDictionary<string, object> environment)
        {
            this.environment = environment;
            //stream = (Stream)environment["owin.ResponseBody"];
            stream = new MemoryStream();
            this.headers = (IDictionary<string, string[]>)environment["owin.ResponseHeaders"];
            setCookies = new Dictionary<string, string>();
        }
        /// <summary>
        /// html静态文件输出
        /// </summary>
        /// <param name="fileName">文件名</param>
        public HtmlWriter(string fileName)
        {
            stream = new FileStream(fileName, FileMode.Create, FileAccess.Write);
        }
        /// <summary>
        /// 写入状态码
        /// </summary>
        /// <param name="statusCode"></param>
        public void WriteStatusCode(int statusCode)
        {
            environment["owin.ResponseStatusCode"] = statusCode;
        }
        /// <summary>
        /// 写入html头
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        public void WriteHeader(string key, string value)
        {
            if (this.headers.ContainsKey(key))
            {
                this.headers[key] = new string[] { value };
            }
            else
            {
                this.headers.Add(key, new string[] { value });
            }
        }
        /// <summary>
        /// 写入html头
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="values">values</param>
        public void WriteHeader(string key,string[] values)
        {
            if (this.headers.ContainsKey(key))
            {
                this.headers[key] = values;
            }
            else
            {
                this.headers.Add(key, values);
            }
        }
        /// <summary>
        /// Add a new cookie and value
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void SetCookie(string key, string value)
        {
            string setCookieString = Uri.EscapeDataString(key) + "=" + Uri.EscapeDataString(value) + "; path=/";
            if (setCookies.ContainsKey(key))
            {
                setCookies[key] = setCookieString;

            }
            else
            {
                setCookies.Add(key, setCookieString);
            }
        }
        /// <summary>
        /// Sets an expired cookie
        /// </summary>
        /// <param name="key"></param>
        public void SetExpiredCookie(string key)
        {
            string deleteCookieString =  Uri.EscapeDataString(key) + "=; expires=Thu, 01-Jan-1970 00:00:00 GMT" ;
            if (setCookies.ContainsKey(key))
            {
                setCookies[key] = deleteCookieString;

            }
            else
            {
                setCookies.Add(key, deleteCookieString);
            }

            WriteHeader("Set-Cookie", deleteCookieString);
        }
        /// <summary>
        /// 写入重定向头
        /// </summary>
        /// <param name="url"></param>
        public void WriteRedirectHeader(string url)
        {
            WriteHeader("Location", url);
        }
        /// <summary>
        /// 输出
        /// </summary>
        public void Flush()
        {
			this.stream.Flush ();
        }
        /// <summary>
        /// 关闭输出流并输出
        /// </summary>
        public void Close()
        {
            if (setCookies.Count > 0)
            {
                this.WriteHeader("Set-Cookie", this.setCookies.Values.ToArray());
            }
            if (this.headers.ContainsKey("Transfer-Encoding"))
            {
                this.headers.Remove("Transfer-Encoding");
            }
            this.WriteHeader("Content-Length", this.contentLength.ToString());
            byte[] buffer = new byte[512];
            Stream outputStream = (Stream)environment["owin.ResponseBody"];
            int readCount = 0;
            stream.Seek(0, SeekOrigin.Begin);
            while ((readCount = stream.Read(buffer, 0, 512)) > 0)
            {
                outputStream.Write(buffer, 0, readCount);
            }
            stream.Dispose();
        }
        /// <summary>
        /// 输出流
        /// </summary>
        /// <param name="buffer">字节数组</param>
        public void Write(byte[] buffer)
        {
            stream.Write(buffer, 0, buffer.Length);
			contentLength += buffer.Length;
        }
        /// <summary>
        /// 输出流
        /// </summary>
        /// <param name="buffer">字节数组</param>
        /// <param name="offset">起始位置</param>
        /// <param name="count">长度</param>
        public void Write(byte[] buffer,int offset,int count)
        {
            stream.Write(buffer, offset, count);
			contentLength += count;
        }
        /// <summary>
        /// 输出字符串
        /// </summary>
        /// <param name="value"></param>
        public void Write(string value)
        {
            byte[] buffer= encoding.GetBytes(value);
            stream.Write(buffer, 0, buffer.Length);
			contentLength += buffer.Length;
        }
    }
}
